package org.jeecg.modules.category.controller;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.vo.DictModel;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.category.entity.AoCategory;
import org.jeecg.modules.category.model.TreeSelectModel;
import org.jeecg.modules.category.service.IAoCategoryService;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 题库分类
 *
 * @author thankgod7
 */
@SuppressWarnings("unused")
@RestController
@RequestMapping("/category")
@Slf4j
public class AoCategoryController {

    @Resource
    private IAoCategoryService iAoCategoryService;

    /**
     * 分页列表查询
     *
     * @param aoCategory param
     * @param pageNo     pageNo
     * @param pageSize   pageSize
     * @return r
     */
    @GetMapping(value = "/rootList")
    public Result<IPage<AoCategory>> queryPageList(AoCategory aoCategory,
                                                   @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                                   @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
        Object o = SecurityUtils.getSubject().getPrincipal();
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        if (oConvertUtils.isEmpty(aoCategory.getPid())) {
            aoCategory.setPid("0");
        }
        Result<IPage<AoCategory>> result = new Result<>();
        QueryWrapper<AoCategory> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("pid", aoCategory.getPid());

        Page<AoCategory> page = new Page<>(pageNo, pageSize);
        IPage<AoCategory> pageList = iAoCategoryService.page(page, queryWrapper);
        result.setSuccess(true);
        result.setResult(pageList);
        return result;
    }

    @GetMapping(value = "/childList")
    public Result<List<AoCategory>> queryPageList(AoCategory aoCategory, HttpServletRequest req) {
        Result<List<AoCategory>> result = new Result<>();
        QueryWrapper<AoCategory> queryWrapper = QueryGenerator.initQueryWrapper(aoCategory, req.getParameterMap());
        List<AoCategory> list = iAoCategoryService.list(queryWrapper);
        result.setSuccess(true);
        result.setResult(list);
        return result;
    }


    /**
     * 添加
     *
     * @param aoCategory p
     * @return r
     */
    @PostMapping(value = "/add")
    public Result<AoCategory> add(@RequestBody AoCategory aoCategory) {
        Result<AoCategory> result = new Result<>();
        try {
            iAoCategoryService.addAoCategory(aoCategory);
            result.success("添加成功！");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            result.error500("操作失败," + e.getMessage());
        }
        return result;
    }

    /**
     * 编辑
     *
     * @param aoCategory p
     * @return r
     */
    @RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
    public Result<AoCategory> edit(@RequestBody AoCategory aoCategory) {
        Result<AoCategory> result = new Result<>();
        AoCategory sysCategoryEntity = iAoCategoryService.getById(aoCategory.getId());
        if (sysCategoryEntity == null) {
            result.error500("未找到对应实体");
        } else {
            try {
                iAoCategoryService.updateAoCategory(aoCategory);
                result.success("修改成功!");
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                result.error500("操作失败," + e.getMessage());
            }
        }
        return result;
    }

    /**
     * 通过id删除
     *
     * @param id id
     * @return r
     */
    @DeleteMapping(value = "/delete")
    public Result<AoCategory> delete(@RequestParam(name = "id") String id) {
        Result<AoCategory> result = new Result<>();
        AoCategory sysCategory = iAoCategoryService.getById(id);
        if (sysCategory == null) {
            result.error500("未找到对应实体");
        } else {
            this.iAoCategoryService.deleteAoCategory(id);
            result.success("删除成功!");
        }

        return result;
    }

    /**
     * 批量删除
     *
     * @param ids ids
     * @return r
     */
    @DeleteMapping(value = "/deleteBatch")
    public Result<AoCategory> deleteBatch(@RequestParam(name = "ids") String ids) {
        Result<AoCategory> result = new Result<>();
        if (ids == null || "".equals(ids.trim())) {
            result.error500("参数不识别！");
        } else {
            this.iAoCategoryService.deleteAoCategory(ids);
            result.success("删除成功!");
        }
        return result;
    }

    /**
     * 通过id查询
     *
     * @param id id
     * @return r
     */
    @GetMapping(value = "/queryById")
    public Result<AoCategory> queryById(@RequestParam(name = "id") String id) {
        Result<AoCategory> result = new Result<>();
        AoCategory sysCategory = iAoCategoryService.getById(id);
        if (sysCategory == null) {
            result.error500("未找到对应实体");
        } else {
            result.setResult(sysCategory);
            result.setSuccess(true);
        }
        return result;
    }

    /**
     * 导出excel
     *
     * @param request r
     */
    @RequestMapping(value = "/exportXls")
    public ModelAndView exportXls(HttpServletRequest request, AoCategory sysCategory) {
        // Step.1 组装查询条件查询数据
        QueryWrapper<AoCategory> queryWrapper = QueryGenerator.initQueryWrapper(sysCategory, request.getParameterMap());
        List<AoCategory> pageList = iAoCategoryService.list(queryWrapper);
        // Step.2 AutoPoi 导出Excel
        ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
        // 过滤选中数据
        String selections = request.getParameter("selections");
        if (oConvertUtils.isEmpty(selections)) {
            mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
        } else {
            List<String> selectionList = Arrays.asList(selections.split(","));
            List<AoCategory> exportList = pageList.stream().filter(item -> selectionList.contains(item.getId())).collect(Collectors.toList());
            mv.addObject(NormalExcelConstants.DATA_LIST, exportList);
        }
        //导出文件名称
        mv.addObject(NormalExcelConstants.FILE_NAME, "题库分类列表");
        mv.addObject(NormalExcelConstants.CLASS, AoCategory.class);
        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("题库分类列表数据", "导出人:" + user.getRealname(), "导出信息"));
        return mv;
    }

    /**
     * 通过excel导入数据
     *
     * @param request req
     * @return r
     */
    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
    public Result<?> importExcel(HttpServletRequest request) {
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            // 获取上传文件对象
            MultipartFile file = entity.getValue();
            ImportParams params = new ImportParams();
            params.setTitleRows(2);
            params.setHeadRows(1);
            params.setNeedSave(true);
            try {
                List<AoCategory> aoCategoryList = ExcelImportUtil.importExcel(file.getInputStream(), AoCategory.class, params);
                //按照编码长度排序
                Collections.sort(aoCategoryList);
                for (AoCategory aoCategoryExcel : aoCategoryList) {
                    String code = aoCategoryExcel.getCode();
                    if (code.length() > 3) {
                        String pCode = aoCategoryExcel.getCode().substring(0, code.length() - 3);
                        String pId = iAoCategoryService.queryIdByCode(pCode);
                        if (StringUtils.isNotBlank(pId)) {
                            aoCategoryExcel.setPid(pId);
                        }
                    } else {
                        aoCategoryExcel.setPid("0");
                    }
                    iAoCategoryService.save(aoCategoryExcel);
                }
                return Result.OK("文件导入成功！数据行数：" + aoCategoryList.size());
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                return Result.error("文件导入失败：" + e.getMessage());
            } finally {
                try {
                    file.getInputStream().close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return Result.error("文件导入失败！");
    }


    /**
     * 加载单个数据 用于回显
     */
    @RequestMapping(value = "/loadOne", method = RequestMethod.GET)
    public Result<AoCategory> loadOne(@RequestParam(name = "field") String field, @RequestParam(name = "val") String val) {
        Result<AoCategory> result = new Result<>();
        try {

            QueryWrapper<AoCategory> query = new QueryWrapper<>();
            query.eq(field, val);
            List<AoCategory> ls = this.iAoCategoryService.list(query);
            if (ls == null || ls.size() == 0) {
                result.setMessage("查询无果");
                result.setSuccess(false);
            } else if (ls.size() > 1) {
                result.setMessage("查询数据异常,[" + field + "]存在多个值:" + val);
                result.setSuccess(false);
            } else {
                result.setSuccess(true);
                result.setResult(ls.get(0));
            }
        } catch (Exception e) {
            e.printStackTrace();
            result.setMessage(e.getMessage());
            result.setSuccess(false);
        }
        return result;
    }

    /**
     * 加载节点的子数据
     */
    @RequestMapping(value = "/loadTreeChildren", method = RequestMethod.GET)
    public Result<List<TreeSelectModel>> loadTreeChildren(@RequestParam(name = "pid") String pid) {
        Result<List<TreeSelectModel>> result = new Result<>();
        try {
            List<TreeSelectModel> ls = this.iAoCategoryService.queryListByPid(pid);
            result.setResult(ls);
            result.setSuccess(true);
        } catch (Exception e) {
            e.printStackTrace();
            result.setMessage(e.getMessage());
            result.setSuccess(false);
        }
        return result;
    }

    /**
     * 加载一级节点/如果是同步 则所有数据
     */
    @RequestMapping(value = "/loadTreeRoot", method = RequestMethod.GET)
    public Result<List<TreeSelectModel>> loadTreeRoot(@RequestParam(name = "async") Boolean async, @RequestParam(name = "pcode") String pcode) {
        Result<List<TreeSelectModel>> result = new Result<>();
        try {
            List<TreeSelectModel> ls = this.iAoCategoryService.queryListByCode(pcode);
            if (!async) {
                loadAllCategoryChildren(ls);
            }
            result.setResult(ls);
            result.setSuccess(true);
        } catch (Exception e) {
            e.printStackTrace();
            result.setMessage(e.getMessage());
            result.setSuccess(false);
        }
        return result;
    }

    /**
     * 递归求子节点 同步加载用到
     */
    private void loadAllCategoryChildren(List<TreeSelectModel> ls) {
        for (TreeSelectModel tsm : ls) {
            List<TreeSelectModel> temp = this.iAoCategoryService.queryListByPid(tsm.getKey());
            if (temp != null && temp.size() > 0) {
                tsm.setChildren(temp);
                loadAllCategoryChildren(temp);
            }
        }
    }

    /**
     * 校验编码
     *
     * @param pid  pid
     * @param code code
     * @return r
     */
    @GetMapping(value = "/checkCode")
    public Result<?> checkCode(@RequestParam(name = "pid", required = false) String pid, @RequestParam(name = "code", required = false) String code) {
        if (oConvertUtils.isEmpty(code)) {
            return Result.error("错误,类型编码为空!");
        }
        if (oConvertUtils.isEmpty(pid)) {
            return Result.OK();
        }
        AoCategory parent = this.iAoCategoryService.getById(pid);
        if (code.startsWith(parent.getCode())) {
            return Result.OK();
        } else {
            return Result.error("编码不符合规范,须以\"" + parent.getCode() + "\"开头!");
        }

    }


    /**
     * 分类字典树控件 加载节点
     *
     * @param pid       pid
     * @param pcode     pcode
     * @param condition condition
     * @return r
     */
    @SuppressWarnings("unchecked")
    @RequestMapping(value = "/loadTreeData", method = RequestMethod.GET)
    public Result<List<TreeSelectModel>> loadDict(@RequestParam(name = "pid", required = false) String pid, @RequestParam(name = "pcode", required = false) String pcode, @RequestParam(name = "condition", required = false) String condition, @RequestParam(name = "async", required = false) boolean async) {
        Result<List<TreeSelectModel>> result = new Result<>();
        //pid如果传值了 就忽略pcode的作用
        if (oConvertUtils.isEmpty(pid)) {
            if (oConvertUtils.isEmpty(pcode)) {
                result.setSuccess(false);
                result.setMessage("加载分类字典树参数有误.[null]!");
                return result;
            } else {
                if (IAoCategoryService.ROOT_PID_VALUE.equals(pcode)) {
                    pid = IAoCategoryService.ROOT_PID_VALUE;
                } else {
                    pid = this.iAoCategoryService.queryIdByCode(pcode);
                }
                if (oConvertUtils.isEmpty(pid)) {
                    result.setSuccess(false);
                    result.setMessage("加载分类字典树参数有误.[code]!");
                    return result;
                }
            }
        }
        Map<String, String> query = null;
        if (oConvertUtils.isNotEmpty(condition)) {
            query = JSON.parseObject(condition, Map.class);
        }
        List<TreeSelectModel> ls = iAoCategoryService.queryListByPid(pid, query);
        if (!async) {
            loadAllCategoryChildren(ls);
        }
        result.setSuccess(true);
        result.setResult(ls);
        return result;
    }

    /**
     * 分类字典控件数据回显[表单页面]
     *
     * @param ids         ids
     * @param delNotExist 是否移除不存在的项，默认为true，设为false如果某个key不存在数据库中，则直接返回key本身
     * @return r
     */
    @RequestMapping(value = "/loadDictItem", method = RequestMethod.GET)
    public Result<List<String>> loadDictItem(@RequestParam(name = "ids") String ids, @RequestParam(name = "delNotExist", required = false, defaultValue = "true") boolean delNotExist, @RequestParam(name = "returnColumn", required = false, defaultValue = "id") String returnColumn) {
        Result<List<String>> result = new Result<>();
        // 非空判断
        if (StringUtils.isBlank(ids)) {
            result.setSuccess(false);
            result.setMessage("ids 不能为空");
            return result;
        }
        // 查询数据
        List<String> textList = iAoCategoryService.loadDictItem(ids, returnColumn, delNotExist);
        result.setSuccess(true);
        result.setResult(textList);
        return result;
    }

    /**
     * [列表页面]加载分类字典数据 用于值的替换
     *
     * @param code code
     * @return r
     */
    @RequestMapping(value = "/loadAllData", method = RequestMethod.GET)
    public Result<List<DictModel>> loadAllData(@RequestParam(name = "code") String code) {
        Result<List<DictModel>> result = new Result<>();
        LambdaQueryWrapper<AoCategory> query = new LambdaQueryWrapper<>();
        if (oConvertUtils.isNotEmpty(code) && !IAoCategoryService.ROOT_PID_VALUE.equals(code)) {
            query.likeRight(AoCategory::getCode, code);
        }
        List<AoCategory> list = this.iAoCategoryService.list(query);
        if (list == null || list.size() == 0) {
            result.setMessage("无数据,参数有误.[code]");
            result.setSuccess(false);
            return result;
        }
        List<DictModel> rdList = new ArrayList<>();
        for (AoCategory c : list) {
            rdList.add(new DictModel(c.getId(), c.getName()));
        }
        result.setSuccess(true);
        result.setResult(rdList);
        return result;
    }

    /**
     * 根据父级id批量查询子节点
     *
     * @param parentIds pids
     * @return data
     */
    @GetMapping("/getChildListBatch")
    public Result<?> getChildListBatch(@RequestParam("parentIds") String parentIds) {
        try {
            QueryWrapper<AoCategory> queryWrapper = new QueryWrapper<>();
            List<String> parentIdList = Arrays.asList(parentIds.split(","));
            queryWrapper.in("pid", parentIdList);
            List<AoCategory> list = iAoCategoryService.list(queryWrapper);
            IPage<AoCategory> pageList = new Page<>(1, 10, list.size());
            pageList.setRecords(list);
            return Result.OK(pageList);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Result.error("批量查询子节点失败：" + e.getMessage());
        }
    }

}
